home *** CD-ROM | disk | FTP | other *** search
/ Macwelt 1 / Macwelt DVD 1.toast / Web-Publishing / HTML-Editoren / Alpha ƒ / Tcl / SystemCode / CorePackages / ISOTime.tcl < prev    next >
Encoding:
Text File  |  2001-02-07  |  12.1 KB  |  281 lines

  1. ## -*-Tcl-*- nowrap
  2.  # ###################################################################
  3.  #  AlphaTcl - core Tcl engine
  4.  # 
  5.  #  FILE: "ISOTime.tcl"
  6.  #                                    created: 1999-08-17 13:46:06 
  7.  #                                last update: 2/7/2001 {9:27:38 PM} 
  8.  #  Author: Frédéric Boulanger
  9.  #  E-mail: Frederic.Boulanger@supelec.fr
  10.  #    mail: Supélec - Service Informatique
  11.  #          Plateau de Moulon, 91192 Gif-sur-Yvette cedex, France
  12.  #     www: http://wwwsi.supelec.fr/fb/fb.html
  13.  #  
  14.  #  Description: 
  15.  #   This extension adds new choices for the second parameter (format)
  16.  #   of the 'mtime' command. "mtime [now] iso" returns the current time
  17.  #   in ISO format, i.e. "1999-08-17T14:55:22Z" for August 17 1999 at
  18.  #   2:55:22 pm.
  19.  #   To be a real ISO format, the final "Z" should be the local time
  20.  #   zone, but I don't know how to get it in Alpha, so I use "Z" which 
  21.  #   means "UTC" or universal time.
  22.  #   Using "relaxed" instead of "iso" yields a more readable date with
  23.  #   a space in place of the 'T' and without the final 'Z'.
  24.  #
  25.  #   The other choices are 'year', 'month', 'day', 'hour', 'minutes',
  26.  #   and 'seconds' to get the respective piece of time information.
  27.  #   
  28.  #   Note: This extension may yield incorrect results if you change the 
  29.  #   time format in the 'Date and Time' control panel while Alpha is running.
  30.  #   
  31.  #   The effective format of the localized time representation is 
  32.  #   determined by the ISOTime::parseLocalizedTime proc which is called
  33.  #   only once for the sake of efficiency.
  34.  #   
  35.  #   If this behaviour may cause problem and you don't use the ISOTime 
  36.  #   procs too often, you may remove the check for ISOTime::regdate and
  37.  #   ISOTime::matchdate at the beginning of ISOTime::brokenDate so that
  38.  #   it rebuilds the regexps at each call.
  39.  #   
  40.  #  History
  41.  # 
  42.  #  modified   by  rev reason
  43.  #  ---------- --- --- -----------
  44.  #  1999-08-17 FBO 1.0 original
  45.  #  1999-08-18 FBO 1.1 added year, month ... keywords for direct access
  46.  #  1999-08-26 FBO 1.2 made the date&time really ISO (YYYY-MM-DDTHH:MM:SSZ)
  47.  #  1999-09-02 VMD 1.3 made work with Alphatk, and fixed some Tcl8 isms
  48.  #  1999-11-04 FBO 1.4 added "relaxed" for a more readable ISO format
  49.  # ###################################################################
  50.  ##
  51. alpha::extension isoTime 1.4 {
  52.     # Time-stamps are in ISO or a shorter, more readable format.
  53.     newPref variable timeStampStyle short global "" "short iso relaxed"
  54.     lunion varPrefs(International) timeStampStyle
  55.     namespace eval ISOTime {}
  56.     if {[info command ISOTime::__mtime] == ""} {
  57.     rename mtime ISOTime::__mtime
  58.     proc mtime {when {format "short"}} {
  59.         switch -- $format {
  60.         relaxed {ISOTime::ISODateAndTimeRelaxed $when}
  61.         iso     {ISOTime::ISODateAndTime $when}
  62.         year    -
  63.         month   -
  64.         day     -
  65.         hour    -
  66.         minutes -
  67.         seconds {
  68.             ISOTime::brokenDate $when bdate
  69.             return $bdate($format)
  70.         }
  71.         default {ISOTime::__mtime $when $format}
  72.         }
  73.     }
  74.     }
  75. } maintainer {
  76.     "Frédéric Boulanger" Frederic.Boulanger@supelec.fr <http://wwwsi.supelec.fr/fb/fb.html>
  77. } uninstall {this-file} help {
  78.     This extension adds new choices for the second parameter
  79.     (format) of the 'mtime' command.  "mtime [now] iso" returns the
  80.     current time in ISO format, i.e. "1999-08-17T14:55:22Z" for
  81.     August 17 1999 at 2:55:22 pm.
  82.     
  83.     To be a real ISO format, the final "Z" should be the local time
  84.     zone, but I don't know how to get it in Alpha, so I use "Z"
  85.     which means "UTC" or universal time.  Using "relaxed" instead
  86.     of "iso" yields a more readable date with a space in place of
  87.     the 'T' and without the final 'Z'.
  88.     
  89.     The other choices are 'year', 'month', 'day', 'hour',
  90.     'minutes', and 'seconds' to get the respective piece of time
  91.     information.
  92.     
  93.     Note: This extension may yield incorrect results if you change
  94.     the time format in the 'Date and Time' control panel while
  95.     Alpha is running.
  96.     
  97.     The effective format of the localized time representation is
  98.     determined by the ISOTime::parseLocalizedTime proc which is
  99.     called only once for the sake of efficiency.
  100.     
  101.     If this behaviour may cause problem and you don't use the
  102.     ISOTime procs too often, you may remove the check for
  103.     ISOTime::regdate and ISOTime::matchdate at the beginning of
  104.     ISOTime::brokenDate so that it rebuilds the regexps at each
  105.     call.
  106. }
  107.  
  108. # Determine the format of the localized time representation and build a
  109. # regular expression to extract each piece of information from this format.
  110. # To get this information, I use the localized string representing
  111. # a known date: March 2 1904 at 5 am, 6 minutes and 7 seconds (5288767 
  112. # MacOS ticks). In this string, I look for '2' which is the day of month,
  113. # for '3' which is the month, for '4' which is the year, for '5' which is
  114. # the minutes and for '7' which is the seconds.
  115. # Once I got the indices of each piece of information in the string, I build
  116. # a list of 'XX YY info' items, where XX is the starting index, YY is the 
  117. # ending index for the 'info' piece of information (day, month, year...).
  118. # I sort this list so that I know in which order the time information is
  119. # given on the current localized version of MacOS.
  120. # Then, I use this list to build a regular expression that matches the 
  121. # localized representation of time, and a matching expression which will
  122. # set the items of the 'datevar' array to the corresponding time 
  123. # information.
  124. # March 2 1904 at 5 am, 6 minutes and 7 seconds is 5288767
  125. # April 3 1905 at 6 am, 7 minutes and 8 seconds is 39593228
  126. proc ISOTime::parseLocalizedTime {} {
  127.     global ISOTime::regdate ISOTime::matchdate alpha::platform
  128.     
  129.     if {${alpha::platform} != "alpha"} {
  130.     set known [ISOTime::__mtime -2043251572 short 1]
  131.     } else {
  132.     set known [ISOTime::__mtime 39593228]
  133.     }
  134.     
  135.     regexp -indices {(.*[^0-9])*(0?3)[^0-9]*.*} $known z pr day  
  136.     regexp -indices {(.*[^0-9])*(0?4)[^0-9]*.*} $known z pr month  
  137.     # '20' is temporary fix for buggy dev version of Alpha
  138.     regexp -indices {(.*[^0-9])*((19|20)?0?5)[^0-9]*.*} $known z pr year  
  139.     regexp -indices {(.*[^0-9])*(0?6)[^0-9]*.*} $known z pr hour  
  140.     regexp -indices {(.*[^0-9])*(0?7)[^0-9]*.*} $known z pr minutes  
  141.     regexp -indices {(.*[^0-9])*(0?8)[^0-9]*.*} $known z pr seconds
  142.     
  143.     set order ""
  144.     lappend order "[format "%.2d" [lindex $day 0]] [format "%.2d" [lindex $day 1]] day"
  145.     lappend order "[format "%.2d" [lindex $month 0]] [format "%.2d" [lindex $month 1]] month"
  146.     lappend order "[format "%.2d" [lindex $year 0]] [format "%.2d" [lindex $year 1]] year"
  147.     lappend order "[format "%.2d" [lindex $hour 0]] [format "%.2d" [lindex $hour 1]] hour"
  148.     lappend order "[format "%.2d" [lindex $minutes 0]] [format "%.2d" [lindex $minutes 1]] minutes"
  149.     lappend order "[format "%.2d" [lindex $seconds 0]] [format "%.2d" [lindex $seconds 1]] seconds"
  150.     set order [lsort $order]
  151.     set ISOTime::regdate ""
  152.     set ISOTime::matchdate ""
  153.     if {[lindex [lindex $order 0] 0] == 0} {
  154.     append ISOTime::regdate {([0-9]*)}
  155.     } else {
  156.     append ISOTime::regdate [string range $known 0 0]
  157.     }
  158.     append ISOTime::matchdate "set date([lindex [lindex $order 0] 2]) \\1;"
  159.     set tmp [ISOTime::int [lindex [lindex $order 0] 1] 1]
  160.     append ISOTime::regdate "\\[string range $known $tmp $tmp]"
  161.     
  162.     append ISOTime::regdate {([0-9]*)}
  163.     append ISOTime::matchdate "set date([lindex [lindex $order 1] 2]) \\2;"
  164.     set tmp [ISOTime::int [lindex [lindex $order 1] 1] 1]
  165.     append ISOTime::regdate "\\[string range $known $tmp $tmp]"
  166.     
  167.     append ISOTime::regdate {([0-9]*)}
  168.     append ISOTime::matchdate "set date([lindex [lindex $order 2] 2]) \\3;"
  169.     set tmp [ISOTime::int [lindex [lindex $order 2] 1] 1]
  170.     append ISOTime::regdate "\\[string range $known $tmp $tmp]"
  171.     
  172.     append ISOTime::regdate {\{?([0-9]*)}
  173.     append ISOTime::matchdate "set date([lindex [lindex $order 3] 2]) \\4;"
  174.     set tmp [ISOTime::int [lindex [lindex $order 3] 1] 1]
  175.     append ISOTime::regdate "\\[string range $known $tmp $tmp]"
  176.     
  177.     append ISOTime::regdate {([0-9]*)}
  178.     append ISOTime::matchdate "set date([lindex [lindex $order 4] 2]) \\5;"
  179.     set tmp [ISOTime::int [lindex [lindex $order 4] 1] 1]
  180.     append ISOTime::regdate "\\[string range $known $tmp $tmp]"
  181.     
  182.     append ISOTime::regdate {([0-9]*)( [aApPmMUhr]+\})?}
  183.     append ISOTime::matchdate "set date([lindex [lindex $order 5] 2]) \\6;"
  184. }
  185.  
  186. # Extract time information from the MacOS ticks 'when', and put it
  187. # in the 'datevar' variable. This information is independent of the
  188. # time display format of your localized version of MacOS.
  189. # Using 'regsub', I apply a regular expression to the localized 
  190. # representation of 'when', and this builds the command that sets
  191. # the items of the 'datevar' array. I evaluate this command, and 
  192. # 'datevar' now holds time information in a localization independent 
  193. # form.
  194. # The regular expression and the transformation expression are built by the
  195. # ISOTime::parseLocalizedTime proc. To save time, this proc is called only if 
  196. # the regular expressions are not defined. This assumes that you don't 
  197. # change the date format while Alpha is running.
  198. # The next step is to trim leading '0' so that the items of the array 
  199. # are simple numbers. 
  200. # A final step adds 1900 or 2000 to the year if it is lower than 100.  
  201. # I use the fact that the MacOS ticks 3029529600 represent 
  202. # January 1st 2000 at 0 hour, 0 minutes and 0 seconds.
  203. # brokenDate $when theDate sets 'theDate' so that:
  204. #   theDate(year)     contains the year of the 'when' MacOS ticks
  205. #   theDate(month)    contains the month of the 'when' MacOS ticks
  206. #   theDate(day)      contains the day of month of the 'when' MacOS ticks
  207. #   theDate(hour)     contains the hour of the 'when' MacOS ticks
  208. #   theDate(minutes)  contains the minutes of the 'when' MacOS ticks
  209. #   theDate(seconds)  contains the seconds of the 'when' MacOS ticks
  210. # January 1st 2000 at 0:00:00 is 3029529600
  211.  
  212. proc ISOTime::brokenDate {{when "now"} {datevar "theDate"}} {
  213.     global ISOTime::regdate ISOTime::matchdate
  214.     upvar $datevar date
  215.     
  216.     if {$when == "now"} {
  217.     set theTicks [now]
  218.     } else {
  219.     set theTicks $when
  220.     }
  221.     
  222.     if {(![info exists ISOTime::regdate]) || (![info exists ISOTime::matchdate])} {
  223.     ISOTime::parseLocalizedTime
  224.     }
  225.     
  226.     regsub [set ISOTime::regdate] [ISOTime::__mtime $theTicks] [set ISOTime::matchdate] dateCmd
  227.     eval $dateCmd
  228.     
  229.     set date(year) [ISOTime::int $date(year)]
  230.     set date(month) [ISOTime::int $date(month)]
  231.     set date(day) [ISOTime::int $date(day)]
  232.     set date(hour) [ISOTime::int $date(hour)]
  233.     set date(minutes) [ISOTime::int $date(minutes)]
  234.     set date(seconds) [ISOTime::int $date(seconds)]
  235.     
  236.     if {$date(year) < 100} {
  237.     if {$theTicks < 3029529600} {
  238.         set date(year) [expr $date(year) + 1900]
  239.     } else {
  240.         set date(year) [expr $date(year) + 2000]
  241.     }
  242.     }
  243.     return $theTicks
  244. }
  245.  
  246. # Work around peculiarity of Tcl that '09' is not an integer,
  247. # but a base 8 number, and that int(09) will give an error.
  248. proc ISOTime::int {what {plus 0}} {
  249.     regsub {^0+([1-9])} $what \\1 what
  250.     return [expr {int($what + $plus)}]
  251. }
  252.  
  253. # Build an ISO representation of the date corresponding to the 'when' MacOS 
  254. # ticks. Uses ISOTime::brokenDate to get a localization independent representation 
  255. # of time. The ISO date is in the form 'YYYY-MM-DD'.
  256. proc ISOTime::ISODate {{when "now"}} {
  257.     ISOTime::brokenDate $when curDate
  258.     return "[format "%.4u" $curDate(year)]-[format "%.2u" $curDate(month)]-[format "%.2u" $curDate(day)]"
  259. }
  260.  
  261. # Same with time added in the form 'THH:MM:SSZ'
  262. proc ISOTime::ISODateAndTime {{when "now"}} {
  263.     ISOTime::brokenDate $when curDate
  264.     return "[format "%.4u" $curDate(year)]-[format "%.2u" $curDate(month)]-[format "%.2u" $curDate(day)]T[format "%.2u" $curDate(hour)]:[format "%.2u" $curDate(minutes)]:[format "%.2u" $curDate(seconds)]Z"
  265. }
  266.  
  267. # Same with time added in the form ' HH:MM:SS' (not strict ISO, but more readable
  268. proc ISOTime::ISODateAndTimeRelaxed {{when "now"}} {
  269.     ISOTime::brokenDate $when curDate
  270.     return "[format "%.4u" $curDate(year)]-[format "%.2u" $curDate(month)]-[format "%.2u" $curDate(day)] [format "%.2u" $curDate(hour)]:[format "%.2u" $curDate(minutes)]:[format "%.2u" $curDate(seconds)]"
  271. }